﻿using Fdb.Model;
using MySql.Data.MySqlClient;
using Oracle.ManagedDataAccess.Client;
using System;
using System.Collections.Generic;
using System.Data;
using System.Reflection;
using System.Text;

namespace Fdb
{
    /// <summary>
    /// 通用方法类
    /// </summary>
    internal class Common
    {
        /// <summary>
        /// 获取第一个主键字段
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <returns>无主键 返回null</returns>
        public static PropertyInfo GetFirstDbKeyField<T>()
        {
            List<PropertyInfo> list = GetDbKeyFieldList<T>();
            if (list.Count > 0) return list[0];
            return null;
        }

        /// <summary>
        /// 获取数据库主键字段
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <returns></returns>
        public static List<PropertyInfo> GetDbKeyFieldList<T>()
        {
            var fields = typeof(T).GetProperties();
            List<PropertyInfo> list = new List<PropertyInfo>();
            foreach (PropertyInfo field in fields)
            {
                DbKey key = (DbKey)Attribute.GetCustomAttribute(field, typeof(DbKey));
                if (key != null) list.Add(field);
            }

            return list;
        }

        /// <summary>
        /// 判断主键特性是否启用了代码级主键序列值填充
        /// </summary>
        /// <param name="field">属性</param>
        /// <returns>布尔结果</returns>
        public static bool IsUseWithDescription(PropertyInfo field)
        {
            var dbKey = (DbKey)Attribute.GetCustomAttribute(field, typeof(DbKey));
            if (dbKey != null)
            {
                return dbKey.IsUseWithDescription;
            }

            return false;
        }

        /// <summary>
        /// 获取数据库只读字段
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <returns></returns>
        public static List<PropertyInfo> GetDbOnlyReadFieldList<T>()
        {
            // 获取当前类中的公共字段
            var fields = typeof(T).GetProperties();
            List<PropertyInfo> list = new List<PropertyInfo>();
            foreach (PropertyInfo field in fields)
            {
                DbOnlyReadField dbOnlyReadField = (DbOnlyReadField)Attribute.GetCustomAttribute(field, typeof(DbOnlyReadField));
                if (dbOnlyReadField != null) list.Add(field);
            }

            return list;
        }

        /// <summary>
        /// 获取属性描述
        /// </summary>
        /// <param name="field"></param>
        /// <returns></returns>
        public static string GetDescription(PropertyInfo field)
        {
            string result = string.Empty;
            var dbKey = (DbKey)Attribute.GetCustomAttribute(field, typeof(DbKey));
            if (dbKey != null) result = dbKey.Description;
            return result;
        }

        /// <summary>
        /// 转换为long型
        /// </summary>
        /// <param name="dataObj"></param>
        /// <returns></returns>
        public static long ConvertToLongWithOutNull(object dataObj)
        {
            if (dataObj == null) return long.MinValue;

            try
            {
                return long.Parse(dataObj.ToString());
            }
            catch (Exception)
            {
                return long.MinValue;
            }
        }

        /// <summary>
        /// 转化为int型
        /// </summary>
        /// <param name="dataObj"></param>
        /// <returns></returns>
        public static int ConvertToIntWithMinValue(object dataObj)
        {
            if (dataObj == null) return int.MinValue;

            try
            {
                return int.Parse(dataObj.ToString());
            }
            catch (Exception)
            {
                return int.MinValue;
            }
        }

        /// <summary>
        /// 转化为int型，结果不为null值
        /// </summary>
        /// <param name="dataObj"></param>
        /// <returns></returns>
        public static int ConvertToIntWithOutNull(object dataObj)
        {
            if (dataObj == null) return int.MinValue;

            try
            {
                return int.Parse(dataObj.ToString());
            }
            catch (Exception)
            {
                return int.MinValue;
            }
        }

        /// <summary>
        /// 获得值对应的数据类型
        /// </summary>
        /// <param name="value"></param>
        /// <returns></returns>
        public static DbType GetDbType(object value)
        {
            if (value == null) return DbType.String;

            Type type = value.GetType();
            switch (type.ToString())
            {
                case "System.Int32": return DbType.Int32;
                case "System.String": return DbType.String;
                //case "System.DateTime": return DbType.Date;  //xxx：出现日期值保存不成功的问题
                case "System.DateTime": return DbType.String; //xxx:日期字段，要用c# 字符串类型保存
                case "System.Double": return DbType.Double;
                case "System.Guid": return DbType.Guid;
                case "System.Drawing.Bitmap": return DbType.Binary;

            }

            return DbType.String;
        }

        /// <summary>
        /// 获得值对应的数据类型
        /// </summary>
        /// <param name="value"></param>
        /// <returns></returns>
        public static MySqlDbType GetMysqlDbType(object value)
        {
            if (value == null) return MySqlDbType.String;
            Type type = value.GetType();
            switch (type.ToString())
            {
                case "System.Int32": return MySqlDbType.Int32;
                case "System.String": return MySqlDbType.String;
                case "System.DateTime": return MySqlDbType.String;
                case "System.Double": return MySqlDbType.Double;
                case "System.Guid": return MySqlDbType.Guid;
                case "System.Drawing.Bitmap": return MySqlDbType.MediumBlob;

            }

            return MySqlDbType.String;
        }

        /// <summary>
        /// 获得sqlserver与c#的数据类型对照
        /// </summary>
        /// <param name="type"></param>
        /// <returns></returns>
        public static string GetSqlserverCSharpType(string type)
        {
            string reval = string.Empty;
            switch (type.ToLower())
            {
                case "int":
                    reval = "int";
                    break;
                case "text":
                    reval = "string";
                    break;
                case "bigint":
                    reval = "int";
                    break;
                case "binary":
                    reval = "System.Byte[]";
                    break;
                case "bit":
                    reval = "boolean";
                    break;
                case "char":
                    reval = "string";
                    break;
                case "datetime":
                    reval = "DateTime";
                    break;
                case "decimal":
                    reval = "double";
                    break;
                case "float":
                    reval = "double";
                    break;
                case "image":
                    reval = "System.Byte[]";
                    break;
                case "money":
                    reval = "System.Decimal";
                    break;
                case "nchar":
                    reval = "string";
                    break;
                case "ntext":
                    reval = "string";
                    break;
                case "numeric":
                    reval = "double";
                    break;
                case "nvarchar":
                    reval = "string";
                    break;
                case "real":
                    reval = "System.Single";
                    break;
                case "smalldatetime":
                    reval = "DateTime";
                    break;
                case "smallint":
                    reval = "int";
                    break;
                case "smallmoney":
                    reval = "System.Decimal";
                    break;
                case "timestamp":
                    reval = "DateTime";
                    break;
                case "tinyint":
                    reval = "System.Byte";
                    break;
                case "uniqueidentifier":
                    reval = "System.Guid";
                    break;
                case "varbinary":
                    reval = "System.Byte[]";
                    break;
                case "varchar":
                    reval = "string";
                    break;
                case "Variant":
                    reval = "Object";
                    break;
                default:
                    reval = "string";
                    break;
            }
            return reval;
        }

        /// <summary>
        /// 转为sqlserver字段类型
        /// </summary>
        /// <param name="value"></param>
        /// <returns></returns>
        public static SqlDbType ChangeToSqlserverType(object value)
        {
            if (value == null)
                return SqlDbType.VarChar;

            Type type = value.GetType();
            switch (type.ToString())
            {
                case "System.Int32": return SqlDbType.Int;
                case "System.String": return SqlDbType.VarChar;
                case "System.DateTime": return SqlDbType.DateTime;
                case "System.Double": return SqlDbType.Decimal;
                case "System.Guid": return SqlDbType.UniqueIdentifier;
                case "System.Drawing.Bitmap": return SqlDbType.Image;

            }
            return SqlDbType.VarChar;
        }

        /// <summary>
        /// 转为oracle字段类型
        /// </summary>
        /// <param name="value"></param>
        /// <returns></returns>
        public static OracleDbType ChangeToOracleType(object value)
        {
            if (value == null)
            {
                return OracleDbType.Varchar2;
            }

            Type type = value.GetType();
            switch (type.ToString())
            {
                case "System.Int32": return OracleDbType.Int32;
                case "System.Decimal": return OracleDbType.Decimal;
                case "System.String": return OracleDbType.Varchar2;
                case "System.DateTime": return OracleDbType.Date;
                case "System.Double": return OracleDbType.Double;
                case "System.Guid": return OracleDbType.Varchar2;
                case "System.Drawing.Bitmap": return OracleDbType.LongRaw;

            }

            return OracleDbType.Decimal;
        }

        /// <summary>
        /// 获得Oracle与c#的数据类型对照
        /// </summary>
        /// <param name="type"></param>
        /// <returns></returns>
        public static string GetOracleCSharpType(string type)
        {
            string reval = string.Empty;
            switch (type.ToLower())
            {
                case "char":
                    reval = "string";
                    break;
                case "nchar":
                    reval = "string";
                    break;
                case "varchar":
                    reval = "string";
                    break;
                case "varchar2":
                    reval = "string";
                    break;
                case "nvarchar2":
                    reval = "string";
                    break;
                case "raw":
                    reval = "string";
                    break;
                case "long":
                    reval = "string";
                    break;
                case "clob":
                    reval = "string";
                    break;
                case "nclob":
                    reval = "string";
                    break;
                case "number":
                    reval = "double";
                    break;
                case "integer":
                    reval = "int";
                    break;
                case "binary_float":
                    reval = "double";
                    break;
                case "binary_double":
                    reval = "double";
                    break;
                case "float":
                    reval = "double";
                    break;
                case "real":
                    reval = "double";
                    break;
                case "decimal":
                    reval = "double";
                    break;
                case "date":
                    reval = "DateTime";
                    break;
                case "timestamp":
                    reval = "DateTime";
                    break;
                default:
                    reval = "string";
                    break;
            }
            return reval;
        }

        /// <summary>
        /// 获取参数格式化值。如字符串字段输出为  '0'，数值字段输出为 0
        /// </summary>
        /// <param name="valObj"></param>
        /// <returns></returns>
        public static string GetRealVal(object valObj)
        {
            if (valObj == null)
            {
                return "null";
            }

            DbType dbType = GetDbType(valObj);
            if (dbType == DbType.Int32 || dbType == DbType.Double)
            {
                return valObj.ToString();
            }

            return "'" + valObj.ToString() + "'";
        }

        /// <summary>
        /// 首字母大写
        /// </summary>
        /// <param name="name"></param>
        /// <returns></returns>
        public static string FirstLetterUpper(string str)
        {
            if (string.IsNullOrEmpty(str)) return string.Empty;
            System.Text.StringBuilder sb = new System.Text.StringBuilder(str);
            char cc = Char.ToUpper(sb[0]);
            sb.Replace(sb[0], cc, 0, 1);
            return sb.ToString();
        }
    }
}
